<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <style>
    path {
      fill: #e3e3e3;
      stroke-width: 1px;
      stroke: #666;
    }
  </style>
</head>
<body>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="../build/flubber.min.js"></script>
<script>
var path = d3.select("svg").append("path"),
    width = 960,
    height = 500,
    currentShapes = randomPolygons(randBetween(2, 6));

animate();

function animate() {
  var nextShapes,
      interpolator;

  // Shapes were just combined, separate into new shapes
  if (currentShapes.length === 1) {
    nextShapes = randomPolygons(randBetween(2, 6));
    interpolator = flubber.separate(currentShapes[0], nextShapes, { single: true });
  // Combine them back together once in a while
  } else if (Math.random() < 0.25) {
    nextShapes = randomPolygons(1);
    interpolator = flubber.combine(currentShapes, flubber.toPathString(nextShapes[0]), { single: true });
  // Keep the existing number of shapes but randomize them
  } else {
    nextShapes = randomPolygons(currentShapes.length);
    interpolator = flubber.interpolateAll(currentShapes, nextShapes, { single: true, match: true });
  }

  currentShapes = nextShapes;

  path
    .transition()
    .delay(300)
    .duration(1000)
    .attrTween("d", function() { return interpolator; })
    .on("end", animate);
}

function randomPolygons(numShapes) {
  return d3.range(numShapes).map(randomPolygon);
}

function randomPolygon() {
  var sides = randBetween(3, 13),
      r = 50 + Math.random() * 100,
      x = r + Math.random() * (width - r * 2),
      y = r + Math.random() * (height - r * 2);

  return d3.range(sides).map(function(i) {
    return [
      Math.cos(Math.PI / 2 + 2 * Math.PI * i / sides) * r + x,
      Math.sin(Math.PI / 2 + 2 * Math.PI * i / sides) * r + y
    ];
  });
}

function randBetween(start, end) {
  return start + Math.floor(Math.random() * (end - start));
}
</script>
